#include "../common/util.hpp"
#include "../common/Log.hpp"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/resource.h>

using namespace util_ns;
using namespace LogModule_ns;

class Runner
{
public:
    // 输入未加工的文件名，内部直接堆in out err重定向到指定文件，然后运行代码，同时对程序进行限制
    static int Run(const std::string &file_name, int cpu_limit, int mem_limit)
    {
        /*
            选择对应名称的in out err文件
            返回值作为信号，使用status查看子进程退出状态码
        */
        DLOG(DEBUG) << "进入运行模块";

        umask(0);
        int status;

        int stdin_fd = open(PathUtil::Stdin(file_name).c_str(), O_CREAT | O_WRONLY, 0666);
        int stdout_fd = open(PathUtil::Stdout(file_name).c_str(), O_CREAT | O_WRONLY, 0666);
        int stderr_fd = open(PathUtil::Stderr(file_name).c_str(), O_CREAT | O_WRONLY, 0666);
        if (stdin_fd == -1 || stdout_fd == -1 || stderr_fd == -1)
        {
            DLOG(ERROR) << "打开标准输入、输入、错误 失败";
            return -1;
        }

        // 开始执行
        int n = fork();
        if (n < 0)
        {
            DLOG(ERROR) << "创建子进程执行任务失败！";
            close(stdin_fd);
            close(stdout_fd);
            close(stderr_fd);
            return -2;
        }
        else if (n == 0)
        {
            dup2(stdin_fd, 0);
            dup2(stdout_fd, 1);
            dup2(stderr_fd, 2);
            limit(cpu_limit, mem_limit);
            execl(PathUtil::Exe(file_name).c_str(), PathUtil::Exe(file_name).c_str(), nullptr);
            exit(1);
        }
        else
        {
            close(stdin_fd);
            close(stdout_fd);
            close(stderr_fd);
            waitpid(n, &status, 0);
            DLOG(INFO) << "运行完毕, info: " << (status & 0x7F);
        }
        // 返回信号编号
        return status & 0x7F;
    }
    static void limit(int _cpu_limit, int _mem_limit)
    {
        struct rlimit cpt_lt;
        cpt_lt.rlim_max = RLIM_INFINITY;
        cpt_lt.rlim_cur = _cpu_limit;
        setrlimit(RLIMIT_CPU, &cpt_lt);

        struct rlimit mem_lt;
        mem_lt.rlim_max = RLIM_INFINITY;
        mem_lt.rlim_cur = _mem_limit * 1024;
        setrlimit(RLIMIT_AS, &mem_lt);
    }
};
